package cn.song.util.easyexcel;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.song.model.DownloadDto;
import cn.song.model.R;
import cn.song.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 下载 Util
 *
 * @author SongRenShuo
 * @date 2025/03/29
 */
@Slf4j
@Component
public class DownloadUtil {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 获取下载列表
     *
     * @param zhangHu 账号
     * @param model   模块(1.订单，2.出库单，3.流水，4.其他)
     * @return {@link List}<{@link DownloadDto}>
     */
    public List<DownloadDto> getDownloadList(String zhangHu, Integer model) {
        List<DownloadDto> downloadDtos = new ArrayList<>();
        if (model != null && !model.equals(0)) {
            downloadDtos.addAll(redisUtil.getList(getExportTaskListKey(model, zhangHu), DownloadDto.class));
        } else {
            for (int i = 1; i <= 4; i++) {
                downloadDtos.addAll(redisUtil.getList(getExportTaskListKey(i, zhangHu), DownloadDto.class));
            }
        }
        if (ObjectUtils.isNotEmpty(downloadDtos)) {
            downloadDtos = downloadDtos.stream().sorted(Comparator.comparing(DownloadDto::getCreateDate).reversed()).collect(Collectors.toList());
        }

        return downloadDtos;
    }


    /**
     * 写入或更新下载列表
     *
     * @param downloadDto 下载DTO
     * @return {@link R }<{@link String}>
     * @date 2025/03/29
     * @author SongRenShuo
     */
    public R<String> updateDownloadList(DownloadDto downloadDto) {
        String zhangHu = downloadDto.getZhangHu();
        Integer model = downloadDto.getModel();
        String key = getExportTaskListKey(model, zhangHu);
        List<DownloadDto> downloadDtos = redisUtil.getList(key, DownloadDto.class).stream()
                .filter(downloadDt -> downloadDt.getUuid().equals(downloadDto.getUuid()))
                .collect(Collectors.toList());

        if (ObjectUtils.isEmpty(downloadDtos)) {
            downloadDto.setUuid(UUID.fastUUID().toString());
            downloadDto.setCreateDate(DateUtil.date());
            downloadDto.setExportStatus(1);
            downloadDto.setProgress(0);
            return R.isSuccess(redisUtil.setList(key, downloadDto, 60 * 60 * 24));
        }

        downloadDtos.forEach(dto -> redisUtil.removeFromList(key, dto));
        return R.isSuccess(redisUtil.setList(key, downloadDto, 60 * 60 * 24));
    }

    /**
     * 终止下载任务 - 完整的任务取消功能
     *
     * @param uuid 下载任务UUID
     * @return 取消结果信息
     * @date 2025/03/29
     * @author SongRenShuo
     */
    public R<String> terminateDownloadTask(String uuid) {
        return terminateDownloadTask(uuid, null, null);
    }

    /**
     * 终止下载任务 - 完整的任务取消功能（优化版本）
     *
     * @param uuid 下载任务UUID
     * @param model 模块类型（可选，用于精确查找）
     * @param account 账户名（可选，用于精确查找）
     * @return 取消结果信息
     * @date 2025/08/29
     * @author SongRenShuo
     */
    public R<String> terminateDownloadTask(String uuid, Integer model, String account) {
        String downloadKey = "exportInBatches_" + uuid;

        // 检查任务是否存在且正在执行
        if (!redisUtil.hasKey(downloadKey)) {
            return R.failed("任务不存在或已结束，无法取消");
        }

        try {
            // 1. 删除执行控制键，停止任务执行
            redisUtil.del(downloadKey);

            // 2. 查找并更新任务列表中的任务状态
            DownloadDto canceledTask;
            if (model != null && StrUtil.isNotBlank(account)) {
                // 精确查找模式
                log.info("使用精确查找模式取消任务，任务ID: {}, 模块: {}, 账户: {}", uuid, model, account);
                canceledTask = findAndUpdateTaskStatusPrecise(uuid, model, account, 5, "用户主动取消任务");
            } else {
                // 遍历查找模式（兼容旧版本）
                log.info("使用遍历查找模式取消任务，任务ID: {}", uuid);
                canceledTask = findAndUpdateTaskStatus(uuid, 5, "用户主动取消任务");
            }

            if (canceledTask != null) {
                // 3. 释放防重复提交锁
                String lockKey = "Export_" + canceledTask.getZhangHu();
                redisUtil.del(lockKey);

                log.info("任务取消成功，任务ID: {}, 账户: {}, 模块: {}", uuid, canceledTask.getZhangHu(), canceledTask.getModel());
                return R.success("任务已成功取消");
            } else {
                log.warn("任务执行已停止，但未找到任务记录进行状态更新，任务ID: {}", uuid);
                return R.success("任务执行已停止");
            }

        } catch (Exception e) {
            log.error("取消任务失败，任务ID: {}", uuid, e);
            return R.failed("取消任务失败：" + e.getMessage());
        }
    }

    /**
     * 精确查找并更新任务状态（优化版本）
     *
     * @param uuid 任务ID
     * @param model 模块类型
     * @param account 账户名
     * @param newStatus 新状态
     * @param description 描述信息
     * @return 更新后的任务对象，未找到时返回null
     * @date 2025/08/29
     * @author SongRenShuo
     */
    private DownloadDto findAndUpdateTaskStatusPrecise(String uuid, Integer model, String account, Integer newStatus, String description) {
        // 直接构建特定的任务列表键
        String taskListKey = getExportTaskListKey(model, account);

        try {
            List<DownloadDto> tasks = redisUtil.getList(taskListKey, DownloadDto.class);

            if (ObjectUtils.isEmpty(tasks)) {
                log.debug("任务列表为空，键: {}", taskListKey);
                return null;
            }

            // 在特定的任务列表中查找目标任务
            for (DownloadDto task : tasks) {
                if (!uuid.equals(task.getUuid())) {
                    continue;
                }
                log.info("精确查找找到任务，任务ID: {}, 模块: {}, 账户: {}", uuid, model, account);

                // 找到任务，更新状态
                task.setExportStatus(newStatus);
                task.setDescription(description);
                task.setEndDate(DateUtil.date());

                // 更新任务列表
                updateDownloadList(task);

                // 更新状态查询键
                String statusKey = "exportInBatches_" + uuid;
                redisUtil.setObject(statusKey, task, 60 * 60 * 24);
                return task;
            }

            log.debug("在特定任务列表中未找到任务，任务ID: {}, 键: {}", uuid, taskListKey);
            return null;

        } catch (Exception e) {
            log.error("精确查找任务失败，任务ID: {}, 模块: {}, 账户: {}", uuid, model, account, e);
            return null;
        }
    }

    /**
     * 查找并更新任务状态（遍历模式，兼容旧版本）
     *
     * @param uuid 任务ID
     * @param newStatus 新状态
     * @param description 描述信息
     * @return 更新后的任务对象，未找到时返回null
     */
    private DownloadDto findAndUpdateTaskStatus(String uuid, Integer newStatus, String description) {
        // 遍历所有可能的模块和账户组合查找任务
        for (int model = 1; model <= 4; model++) {
            // 这里需要遍历可能的账户，由于无法获取所有账户列表，
            // 我们采用一个更好的方法：通过Redis的scan命令查找
            Set<String> taskListKeys = redisUtil.keys("EXPORT_TASKLIST_" + model + "_*");

            for (String taskListKey : taskListKeys) {
                List<DownloadDto> tasks = redisUtil.getList(taskListKey, DownloadDto.class);

                for (DownloadDto task : tasks) {
                    if (!uuid.equals(task.getUuid())) {
                        continue;
                    }
                    // 找到任务，更新状态
                    task.setExportStatus(newStatus);
                    task.setDescription(description);
                    task.setEndDate(DateUtil.date());

                    // 更新任务列表
                    updateDownloadList(task);

                    // 更新状态查询键
                    String statusKey = "exportInBatches_" + uuid;
                    redisUtil.setObject(statusKey, task, 60 * 60 * 24);
                    return task;
                }
            }
        }

        return null;
    }

    /**
     * 获取 导出任务列表Redis Key
     *
     * @param model 型
     * @param zhangHu 账户
     * @date 2025/03/29
     * @return {@link String }
     * @author SongRenShuo
     */
    private static String getExportTaskListKey(Integer model, String zhangHu) {
        return StrUtil.format("EXPORT_TASKLIST_{}_{}", model, zhangHu);
    }

}
